// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#define  PLAYER_HANDBAGSIZE 120.0f

#include "GameFramework/Character.h"
#include "ResourceManager.h"
#include "CGameManager.h"
#include "UIManager.h"
#include "HoldHand.h"
#include "WeaponOwner.h"
#include "Bag.h"
#include "PerceptionNotify.h"
#include "Isalong2.h"
#include "CPlayerCharacter.generated.h"

UCLASS()
class ISALONG2_API ACPlayerCharacter : public ACharacter, public IWeaponOwner , public IBeHurtable
{
	GENERATED_BODY()

public:
	// Sets default values for this character's properties
	ACPlayerCharacter();


	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

	// Called a few seconds after begin play
	void AfterBeginPlay();
	
	// Called every frame
	virtual void Tick( float DeltaSeconds ) override;

	// Called to bind functionality to input
	virtual void SetupPlayerInputComponent(class UInputComponent* InputComponent) override;

//Character basic state (about control)
public:
	// Run Speed
	float _runSpeed=600.0f;

	// Walk Speed;
	float _walkSpeed=400.0f;

	// Auxiliary Speed
	float _auxiliarySpeed = 250.0f;

	// turn rate
	float _baseTurnRate = 45.0f;
	
	// turn up rate
	float _baseLookupRate = 45.0f;
	
	// states:
	bool _isRunning = false;
	
	bool _isReloading = false;

	bool _isAuxiliary = false;

	bool _blockActionInput = false;

	//////////////////////////////////////////////////////////////////////////
	//						Player Game State Start							//
	//////////////////////////////////////////////////////////////////////////

	float _playerStateHungryTimer = 0;
	float _hungryDecentFeq = 5;
	int _hungryDecentBasic = 1;
	int _hungryDecentMax = 3;

	float _playerStateWaterTimer = 0;
	float _waterDecentFeq = 4;
	int _waterDecentBasic = 1;
	int _waterDecentMax = 4;

	float _playerStateImmunityTimer = 0;
	float _immunityDecentFeq = 3;
	int _immunityDecentBasic = 2;
	int _immunityIncreaseBasic = 1;

	// update player state in runtime
	void PlayerHealthStateCheck(float DeltaTime);
	//////////////////////////////////////////////////////////////////////////
	//						Player Game State End							//
	//////////////////////////////////////////////////////////////////////////


	//////////////////////////////////////////////////////////////////////////
	//					FOV Dynamic Aim Change Effect Begin					//
	//////////////////////////////////////////////////////////////////////////
	FTimeline _fovTimeLine;

	const TCHAR* _fovAuxiliaryTimeLine=TEXT("CurveFloat'/Game/BrainInVst/Curve/FOVOpenClose.FOVOpenClose'");
	float _fovAuxiliaryTimeLineLength = 0.15f;

	const TCHAR* _fovRunningTimeLine=TEXT("CurveFloat'/Game/BrainInVst/Curve/FOVRunOpenClose.FOVRunOpenClose'");
	float _fovRunningTimeLineLength = 0.75f;

	void FOVDynamicStart(float timelineLength,const TCHAR* curvePath);
	void FOVDynamicEnd(float timelineLength,const TCHAR* curvePath);

	UFUNCTION()
	void FOVDynamicInterp(float value);

	UFUNCTION()
	void FOVDynamicTimeLineCheck(float delta);

	//////////////////////////////////////////////////////////////////////////
	//					FOV Dynamic Aim Change Effect end					//
	//////////////////////////////////////////////////////////////////////////



	//////////////////////////////////////////////////////////////////////////
	//					Depth Of Field Bag Open Close Effect				//
	//////////////////////////////////////////////////////////////////////////

	FTimeline _openDepthOfFieldTimeLine;
	bool _bOpenBag = false;

	void DepthOfFieldUIOpenStart();
	void DepthOfFieldUICloseStart();

	UFUNCTION()
	void DepthOfFieldUIInterp(float value);

	UFUNCTION()
	void DepthOfFieldUIOpenEnd();

	UFUNCTION()
	void DepthOfFieldUICloseEnd();

	void DFBagTimeLineCheck(float delta);
	//////////////////////////////////////////////////////////////////////////
	//					Depth Of Field Bag Open Close Effect				//
	//////////////////////////////////////////////////////////////////////////

	//////////////////////////////////////////////////////////////////////////
	//					PerceptionSphere Start								//
	//////////////////////////////////////////////////////////////////////////
	FTimeline _perceptionTimeline;
	bool _isPerceptionOn = false;
	bool _isPerceptionOpenAnimation = false;
	float _perceptionStrength = 0.0f;
	float _perceptionValueRange = 2000;
	UMaterialInstanceDynamic* _perceptionDynamic;

	bool _allowPerceptionOneClickClose = false; /* Use this for other place close perception */

	UCurveFloat* _bloomIntensity;
	UCurveFloat* _bloomThreshold;
	UCurveFloat* _DOFFBS;
	UCurveFloat* _DOFFocalDistance;
	UCurveFloat* _DOFFocalRegion;
	UCurveFloat* _DOFFTR;
	UCurveFloat* _DOFNTR;
	UCurveFloat* _filmSaturation;
	UCurveFloat* _sceneColorVI;
	UCurveFloat* _WBTemp;
	UCurveFloat* _WBTint;

	bool _perceptionStartDirection = true;

	void PerceptionEffectStart();
	void PerceptionEffectEnd();

	UFUNCTION()
	void PerceptionInterp(float val);

	UFUNCTION()
	void PerceptionEnd();

	UFUNCTION()
	void PerceptionTimelineCheck(float delta);

	void PerceptionAnimTick(float DeltaTime);

	TArray<IPerceptionNotify*> _perceptionObjects;

	UFUNCTION()
	void PerceptionBeginOverlap(AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);

	UFUNCTION()
	void PerceptionEndOverlap(AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);
	//////////////////////////////////////////////////////////////////////////
	//					PerceptionSphere End								//
	//////////////////////////////////////////////////////////////////////////

// Components
private:
	// The camera that use for user`s view
	UCameraComponent* _camera;

	// The sk mesh for character
	USkeletalMeshComponent* _mesh;

	// The glim that character hold
	USpotLightComponent* _glim;
	
	// Effect depth
	UPostProcessComponent* _depthPost;

	// Main effect
	UPostProcessComponent* _playerPost;

	// particle emitter
	UParticleSystemComponent* _particleSys;

	// for Perception function
	UStaticMeshComponent* _perceptionSphere;

private:
	// weapon
	AWeaponBase* _holdingWeapon = nullptr;

	shared_ptr<Bag> _userBag = nullptr;

// implementation of interface IWeaponOwner
public:
	// play montage
	void OnPlayMontage(UAnimMontage* montage) override;

	void MontagePause(UAnimMontage* montage) override;

	void OnStopMontage(float time) override;

	void OnBulletChangeCallBack() override;

	AActor* GetOwnerActor() override;

	FVector GetOwnerEyeLocation() override;

	FVector GetOwnerEyeDirection() override;

	bool IsAuxiliaryMode() override;

	UFUNCTION()
	void Test();
// game play API
public:
	// change the weapon current hold by id(1.search the user`s bag ,if has change it if not return)
	void ChangeWeaponByID(int id);

	// change the weapon current hold by id(1.search the user`s bag ,if has change it if not return)
	void ChangeWeaponByGuid(FGuid guid);

	// for ui to get the bag data immediately
	TArray<Item> GetBagDatas();

	// returnt the current hold item
	Item GetCurrentHold();

	// remove some items from the player`s bag
	void RemoveItemFromBags(int32 id, int32 count);

	// drop item from the player`s bag
	void DropItemFromBags(int32 id, int32 count);

	// add some items to the player`s bag
	void AddItemToBags(int32 id, int32 count);

	// get the reload remain by id
	int GetReloadRemainById(int id);

// for blueprint
public:

	UFUNCTION(BlueprintCallable, category = "AnimationInfo")
	bool GetIsRunning();

	// bp call it to get the weapon type
	UFUNCTION(BlueprintCallable,category="Weapon")
	int32 GetWeaponType();

	// get is auxiliary
	UFUNCTION(BlueprintCallable,category="AnimationInfo")
	bool GetIsAuxiliary();

	// the function that called by bp
	UFUNCTION(BlueprintCallable,category="AnimCallBack")
	void OnWeaponReloadComplete();

	// after fire animation
	UFUNCTION(BlueprintCallable, category = "AnimCallBack")
	void OnFireAnimComplete();

	// fire animation fire
	UFUNCTION(BlueprintCallable, category = "AnimCallBack")
	void OnFireAnimationFired();

	UFUNCTION(BlueprintCallable, category = "AnimCallBack")
	void OnFootStep();


	//////////////////////////////////////////////////////////////////////////
	//				Dynamic Depth of field Begin							//
	//////////////////////////////////////////////////////////////////////////
private:
	// indicate whether use or not
	bool _bDynamicDepthOfField = false;

	void DynamicDepthOfFieldCheck();

	//////////////////////////////////////////////////////////////////////////
	//				Dynamic Depth of field End							//
	//////////////////////////////////////////////////////////////////////////


// Movement
private:
	// mouse behavior
	void AddControllerYawInput(float Val) override;
	void AddControllerPitchInput(float Val) override;

	// move forward
	void MoveForward(float value);
	//move right
	void MoveRight(float value);
	// turn at rate
	void TurnAtRate(float value);
	// look up at rate
	void LookUpAtRate(float value);

	// get the remain count for reload
	int GetReloadRemain();

	// addition
	void BeginRun();
	void EndRun();

	// mouse mid key action
	void BeginAdditionalAction();
	void EndAdditionalAction();

	// the action called by Begin and End
	void ActionBeginGlim();
	void ActionEndGlim();

	// fire
	void BeginFire();
	void EndFire();

	// reload
	void BeginReload();
	void EndReload();

	// Perception
	void BeginPerception();
	void EndPerception();

	// Interact
	void InteractBegin();
	void InteractEnd();

	// InteractPlus
	void InteractPlusBegin();
	void InteractPluseEnd();

	// BagOpen
	void BeginOpenBag();
	void EndOpenBag();

	// Select Ring Open
	void OpenCloseSelectRing();
	bool _isSelectRingOpen=false;

	// Auxiliary
	void BeginAuxiliary();
	void EndAuxiliary();

	// use mouse wheel to change item
	void ChangeItemRate(float value);

	//////////////////////////////////////////////////////////////////////////
	//					Avatar took up item define	start					//
	//////////////////////////////////////////////////////////////////////////

	// ray trace for took up able item detection
	void TookItemRayTraceCheck();

	AInteractItem* _readyTookUpItem=nullptr;

	//////////////////////////////////////////////////////////////////////////
	//					Avatar took up item define end						//
	//////////////////////////////////////////////////////////////////////////
};
